﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;
using XSTDZ.ERP.Core.Specifications;

namespace XSTDZ.ERP.Application.Implements
{
    public class ProductDeliveryBillServiceImpl : ApplicationServiceBase, IProductDeliveryBillService
    {
        IRepository<ProductDeliveryBill> _billRepository;
        IRepository<ProductDeliveryBillDetail> _billItemRepository;
         IRepository<Stock> _stockRepository;

         IRepository<ProductInBill> _productRepository;

         public ProductDeliveryBillServiceImpl(IRepositoryContext repositoryContext,
             IRepository<ProductDeliveryBill> billRepository,
            IRepository<ProductDeliveryBillDetail> billItemRepository, 
             IRepository<ProductInBill> productRepository,
             IRepository<Stock> stockRepository)
            : base(repositoryContext)
        {
            this._billRepository = billRepository;
            this._billItemRepository = billItemRepository;
           this._stockRepository = stockRepository;

           this._productRepository = productRepository;
        }


         public Dictionary<ProductDeliveryBillDto, IEnumerable<ProductDeliveryBillDetailDto>> GetBillAndDetails(Guid outBillId)
         {
             var productOutBill = this._billRepository.GetByKey(outBillId);
             var billDto = Mapper.Map<ProductDeliveryBill, ProductDeliveryBillDto>(productOutBill);
             var billDetailDto = Mapper.Map<IEnumerable<ProductDeliveryBillDetail>, IEnumerable<ProductDeliveryBillDetailDto>>(productOutBill.ProductDeliveryBillDetails.AsEnumerable());
             var result = new Dictionary<ProductDeliveryBillDto, IEnumerable<ProductDeliveryBillDetailDto>>();
             result.Add(billDto, billDetailDto);
             return result;
         }

         public Guid AddProductDeliveryBill(ProductDeliveryBillDto productDeliveryBillDto)
         {
             throw new NotImplementedException();
         }

         public Guid AddProductDeliveryBill(ProductDeliveryBillDto productDeliveryBillDto, IEnumerable<ProductDeliveryBillDetailDto> productDeliveryBillDetailDtos, bool isValidateStock)
         {
             if (isValidateStock)
             {
                 if (IsHasStockTooBigNum(productDeliveryBillDetailDtos)) { return Guid.Empty; }//检测是否有超过库存数量的销售单据
             }
             var productDeliveryBill = Mapper.Map<ProductDeliveryBillDto, ProductDeliveryBill>(productDeliveryBillDto);
             var productDeliveryBillDetails = Mapper.Map<IEnumerable<ProductDeliveryBillDetailDto>, IEnumerable<ProductDeliveryBillDetail>>(productDeliveryBillDetailDtos);
             productDeliveryBill.Init().AddDetails(productDeliveryBillDetails);

             productDeliveryBill.UpdateDate = DateTime.Now;
             productDeliveryBill.UpdateID = productDeliveryBill.CreateID;

             this._billRepository.Add(productDeliveryBill);
             this.Context.Commit();
             return productDeliveryBill.Id;
         }

         public Guid AddProductDeliveryBill(Guid productDeliveryBillId, IEnumerable<ProductDeliveryBillDetailDto> productDeliveryBillDetailDtos)
         {
             throw new NotImplementedException();
         }

        
         public void UpdateProductDeliveryBill(ProductDeliveryBillDto productDeliveryBillDto)
         {
             throw new NotImplementedException();
         }

         public void UpdateProductDeliveryBill(Guid productDeliveryBillId, IEnumerable<ProductDeliveryBillDetailDto> productDeliveryBillDetailDtos)
         {
             throw new NotImplementedException();
         }

         public Guid UpdateProductDeliveryBill(ProductDeliveryBillDto productDeliveryBillDto, IEnumerable<ProductDeliveryBillDetailDto> productDeliveryBillDetailDtos, bool isValidateStock)
         {
             if (isValidateStock)
             {
                 if (IsHasStockTooBigNum(productDeliveryBillDetailDtos)) { return Guid.Empty; }//检测是否有超过库存数量的销售单据
             }
             var profitAndLossBill = this._billRepository.GetByKey(productDeliveryBillDto.Id);
          //   profitAndLossBill.ProductDeliveryBillDetails = profitAndLossBill.ProductDeliveryBillDetails.Where(t => t.Deleted != 1).ToList();
             productDeliveryBillDto.CreateTime = profitAndLossBill.CreateTime;
             var targetBill = Mapper.Map(productDeliveryBillDto, profitAndLossBill);
          
             //处理明细
             var productCheckBillDetails = Mapper.Map<IEnumerable<ProductDeliveryBillDetailDto>, IEnumerable<ProductDeliveryBillDetail>>(productDeliveryBillDetailDtos);

             var updateItems = new List<ProductDeliveryBillDetail>();
             var insertItems = new List<ProductDeliveryBillDetail>();
             var itemIds = profitAndLossBill.ProductDeliveryBillDetails.Select(d => d.Id).Cast<Guid>();

             productCheckBillDetails.Each(
                 pd =>
                 {
                     if (itemIds.Contains(pd.Id))
                     {
                         updateItems.Add(pd);
                     }
                     else
                     {
                         insertItems.Add(pd.Init());
                     }
                 }
                 );
             if (updateItems.Count() != 0)
             {
                 foreach (var p in targetBill.ProductDeliveryBillDetails)
                 {
                     foreach (var m in updateItems)
                     {
                         if (m.Id == p.Id)
                         {
                             p.StockID = m.StockID;
                             p.SenderCount = m.SenderCount;
                             p.Remarks = m.Remarks;
                             p.Pack = m.Pack;
                             p.ClientNo = m.ClientNo;
                             break;
                         }
                     }
                 }
             }
             if (insertItems.Count() != 0)
             {
                 this._billItemRepository.Add(insertItems);
             }
             try
             {
                 this._billRepository.Update(targetBill);
                 this.Context.Commit();
             }
             catch (Exception ex)
             {
                 
                 throw;
             }
             return targetBill.Id;
            
         }

         public void ConvertProductDeliveryBillDeleteState(Guid productDeliveryBillId)
         {
             var pbill = this._billRepository.GetByKey(productDeliveryBillId);
             pbill.Deleted = 1;
             pbill.ProductDeliveryBillDetails.Each(d => { d.Deleted = 1; });
             this._billRepository.Update(pbill);
             this.Context.Commit();
         }

         public void ConvertProductDeliveryBillDeleteState(Guid productDeliveryBillId, IEnumerable<Guid> profitAndLossBillDetailIds)
         {
             var pbill = this._billRepository.GetByKey(productDeliveryBillId);
             pbill.ProductDeliveryBillDetails.Each(d =>
             {
                 if (profitAndLossBillDetailIds.Contains(d.Id))
                 {
                     d.Deleted = 1;
                 }
             });
             this._billRepository.Update(pbill);
             this.Context.Commit();
         }

         public ProductDeliveryBillDto GetProductDeliveryBill(Guid productDeliveryBillId)
         {
             var productCheckBill = this._billRepository.GetByKey(productDeliveryBillId);
             //if (productCheckBill.Checkor == null) { productCheckBill.Checkor = new User(); };
             productCheckBill.Affirmor = productCheckBill.Affirmor ?? new User();
             productCheckBill.Sender = productCheckBill.Sender ?? new User();
             productCheckBill.Deliveryor = productCheckBill.Deliveryor ?? new User();
             productCheckBill.Delivery = productCheckBill.Delivery ?? new Org();
             return Mapper.Map<ProductDeliveryBill, ProductDeliveryBillDto>(productCheckBill);
         }
         public IEnumerable<ProductDeliveryBillDto> GetProductDeliveryBills(IEnumerable<Guid> productDeliveryBillIds)
         {
             var productCheckBills = this._billRepository.GetAll(t => productDeliveryBillIds.Contains(t.Id));
             //productCheckBills.Each(t =>
             //{
             //    t.Affirmor = t.Affirmor ?? new User();
             //    t.Sender = t.Sender ?? new User();
             //    t.Deliveryor = t.Deliveryor ?? new User();
             //    t.Delivery = t.Delivery ?? new Dept();
             //});
             return Mapper.Map<IEnumerable<ProductDeliveryBill>, IEnumerable<ProductDeliveryBillDto>>(productCheckBills);
         }
         public IEnumerable<ProductDeliveryBillDto> GetProductDeliveryBills(int pageIndex, int pageSize,bool?isDeleted,bool? isAudited)
         {
             ISpecification<ProductDeliveryBill> spec = Specification<ProductDeliveryBill>.Eval(t=>true);
             if (isDeleted.HasValue)
             {
                 int _deleted = isDeleted.Value ? 1 : 0 ;
                 spec = spec.And(Specification<ProductDeliveryBill>.Eval(t => t.Deleted == _deleted));
             }
             if (isAudited.HasValue)
             {
                 int _isAudited = isAudited.Value ? 1 : 0;
                 spec = spec.And(Specification<ProductDeliveryBill>.Eval(t => t.AffirmState == _isAudited));
             }
             var orderby = new OrderByParameter<ProductDeliveryBill>(m => m.CreateTime, SortOrder.Descending);
             var productCheckBills = this._billRepository.GetAll(spec,pageIndex, pageSize, new[] { orderby });
             productCheckBills.Each(t => { 
                 t.Affirmor = t.Affirmor ?? new User();
                 t.Sender = t.Sender ?? new User();
                 t.Deliveryor = t.Deliveryor ?? new User();
                 t.Delivery = t.Delivery ?? new Org(); 
             });
             return Mapper.Map<IEnumerable<ProductDeliveryBill>, IEnumerable<ProductDeliveryBillDto>>(productCheckBills);
         }
         #region 提交(修改库存）
        //厂里发出来的货，不会更新库存，因为厂里没有库存数据
         public void ConfirmProductDeliveryNoStock(IList<Guid> billIds, Guid userId)
         {
             var bills = this._billRepository.GetAll(t => billIds.Contains(t.Id)).ToList();
             if (bills != null && bills.Count() != 0)
             {
                 bills.Each(t =>
                 {
                     t.BillState = 1;
                 });
                 this._billRepository.Update(bills);

                 this.Context.Commit();
             }

         }
         public void ConfirmProductDelivery(IList<Guid> billIds, Guid userId)
         {
             var bills = this._billRepository.GetAll(t => billIds.Contains(t.Id)).ToList();
             if (bills != null && bills.Count() != 0)
             {
                 bills.Each(t =>
                 {
                     t.BillState = 1;
                     UpdateToStock(t);//更新库存
                 });
                 this._billRepository.Update(bills);
                
                 this.Context.Commit();
             }

         }
         private void UpdateToStock(ProductDeliveryBill pbill)
         {
             var updateStocks = new List<Stock>();
             // var pbill = this._billRepository.GetByKey(productDeliveryBillId);
             pbill.ProductDeliveryBillDetails.Each(d =>
             {
                
                     updateStocks.Add(new Stock
                     {
                         Id = d.StockID,
                         StockCount = -d.SenderCount //发货数量
                     });
                 
             });

             StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
             stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存

         }
         #endregion
         //这里的库存还需要确认，是不是发货了，同时在一个仓库扣减，别一个仓库增加
         public void UpdateToStock(Guid productDeliveryBillId, IEnumerable<Guid> productDeliveryBillDetailIds)
         {
             var updateStocks = new List<Stock>();
             var pbill = this._billRepository.GetByKey(productDeliveryBillId);
             pbill.ProductDeliveryBillDetails.Each(d =>
             {
                 if (productDeliveryBillDetailIds.Contains(d.Id))
                 {
                     updateStocks.Add(new Stock
                     {
                         Id = d.StockID,
                         StockCount = d.SenderCount //发货数量
                     });
                 }
             });
             if (updateStocks.Count() != 0)
             {
                 StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                 stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
                 this.Context.Commit();
             }
         }

         public void Audit(IList<Guid> deliveryIds, Guid createId,string minProductInNo,int len)
         {
             var pbills = this._billRepository.GetAll(t => deliveryIds.Contains(t.Id));
             pbills.Each(pbill =>
             {
                 pbill.AffirmorID = createId;
                 pbill.AffirmDate = DateTime.Now;
                 pbill.AffirmState = 1;
             });
             _billRepository.Update(pbills);//更新库存
             #region 导入确认库存
             ImportDeliveryToProductIn(deliveryIds, createId, minProductInNo, len);
             #endregion
             this.Context.Commit();
         }

         public void UnAudit(IList<Guid> deliveryIds, Guid createId, string minProductInNo, int len)
         {
             var pbills = this._billRepository.GetAll(t => deliveryIds.Contains(t.Id));
             pbills.Each(pbill =>
             {
                 //pbill.AffirmorID = createId;
                 //pbill.AffirmDate = DateTime.Now;
                 pbill.BillState =0;
             });
             _billRepository.Update(pbills);
             this.Context.Commit();
         }
         public void AddProductDeliveryBillDetail(Guid productInBillId, ProductDeliveryBillDetailDto productCheckBillDetailDto)
         {
             throw new NotImplementedException();
         }

         public void UpdateProductDeliveryBillDetail(Guid productInBillId, IEnumerable<ProductDeliveryBillDetailDto> productDeliveryBillDetailDtos)
         {
             throw new NotImplementedException();
         }

         public ProductDeliveryBillDetailDto GetProductDeliveryBillDetail(Guid productCheckBillDetailId)
         {
             //var productCheckBill = this._billRepository.GetByKey(productCheckBillDetailId);
             //return Mapper.Map<ProductDeliveryBillDetail, ProductDeliveryBillDetailDto>(productCheckBill);
             throw new NotImplementedException();
         }

         public IEnumerable<ProductDeliveryBillDetailDto> GetProductDeliveryBillDetails(Guid productDeliveryBillId)
         {
             var productCheckBills = this._billItemRepository.GetAll(d => d.ProductDeliveryBillID == productDeliveryBillId);
             return Mapper.Map<IEnumerable<ProductDeliveryBillDetail>, IEnumerable<ProductDeliveryBillDetailDto>>(productCheckBills);
         }


         public string GetMaxBillNo()
         {
               var orderby = new OrderByParameter<ProductDeliveryBill>(m => m.CreateTime, SortOrder.Descending);
               var billNo = this._billRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
               return billNo==null?string.Empty:billNo.DeliveryNo;
         }

        #region 导入确认后的出库单据到入库单中
          //导入确认的收货单到入库单
         private void ImportDeliveryToProductIn(IList<Guid> deliveryIds, Guid createId,string minProductInNo,int len)
         {

             var deliveryList = this._billRepository.GetAll(t => deliveryIds.Contains(t.Id));
             var productInList = new List<ProductInBill>();
             productInList.Clear();

            bool isFirst=true;
             foreach (var item in deliveryList)
             {
                 #region 转换发货单到入库单
                 var proIn = new ProductInBill()
                 {
                     CreateID = createId,
                     StorehouseID=item.Delivery.Storehouses.FirstOrDefault().Id,//wareHourseId,
                     ProductInBillNo = GetNextProductIn(minProductInNo, len, isFirst),
                     ProductInDate = DateTime.Now,
                     SenderID = item.SenderID,
                     EmployeeID = createId,
                     SourceOrgID = item.WareHourse.OrgID,
                     Remarks = "导入"

                 };
                 proIn.Init();
                 #endregion
                 #region 转化明细
                 item.ProductDeliveryBillDetails.Each(t =>
                 {
                     proIn.ProductInBillDetails.Add(new ProductInBillDetail
                     {
                         ProductID = t.Stock.ProductID??Guid.NewGuid(),
                         InlCount = t.SenderCount,
                         ShelfNumber = "导入",
                         Remarks = t.Remarks
                     }.Init());
                 });
                 productInList.Add(proIn);
                 #endregion
                 isFirst = false;
             }

             #region 写入数据库
             ProductInServiceImpl proInImpl = new ProductInServiceImpl(this.Context, _productRepository, null, this._stockRepository);
             proInImpl.AddProductInBill(productInList);
             #endregion

         }
        //按顺序生成单号
         private string GetNextProductIn(string productInNo,int len,bool isMinNo)
         {
             if (isMinNo)
             {
                 return productInNo;
             }
             var lastSec = productInNo.Substring(productInNo.Length - len - 1, len);
            var newSec= Convert.ToInt32(lastSec) + 1;
            return productInNo.Replace(lastSec, string.Format("{0:" + InitLastNo(len) + "}", newSec));
         }
         private string InitLastNo(int len)
         {
             string str = "";
             for (int i = 0; i < len; i++)
             {
                 str += "0";
             }
             return str;
         }
        #endregion
         /// <summary>
         /// 检测是否有超过库存数量的销售单据
         /// </summary>
         /// <param name="ps"></param>
         /// <returns></returns>
         private bool IsHasStockTooBigNum(IEnumerable<ProductDeliveryBillDetailDto> ps)
         {
             if (ps != null && ps.Count() > 0)
             {
                 foreach (var item in ps)
                 {
                     if (item.SenderCount <= 0 || item.SenderCount <= 0)
                     {
                         return true;
                         break;
                     }
                     if (_stockRepository.Exists(s => s.Id == item.StockID && s.StockCount < item.SenderCount))
                     {
                         return true;
                         break;
                     }
                 }
             }
             return false;
         }



    }

}
